﻿/*
 * Created by SharpDevelop.
 * User: MyWife
 * Date: 5/18/2008
 * Time: 11:22 AM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
 using System;
 
 namespace popLib{
	 public class DateTimeLib{
	 	
	 	//get date only
		public static DateTime getDate()
		{
			return new DateTime( DateTime.Now.Date.Year, DateTime.Now.Date.Month, DateTime.Now.Date.Day );
		}
	
		//get date and time
		public static DateTime getDateTime()
		{
			return DateTime.Now;
		}
	
		//get string date with form as "MM/dd/yyyy"
		public static string getDateString()
		{
			return DateTime.Now.Date.Month +"/"+ DateTime.Now.Date.Day +"/"+ DateTime.Now.Date.Year;
		}
	
		//get string time with form as "hh.mm"
		public static string getTimeString()
		{
			int min = DateTime.Now.Minute;
			int hou = DateTime.Now.Hour;
			if(min < 10) return hou +".0"+ min;
			return hou +"."+ min;
		}
		
		
		/// <summary>
		/// get date from string with form as "MM/dd/yyyy"
		/// if incorrect input -> return current date
		/// </summary>
		/// <param name="val"></param>
		/// <returns></returns>
		public static DateTime GetDateFromString(string val)
		{
			if(val.IndexOf("/") == val.LastIndexOf("/")) return getDate();
			string[] str = val.Split('/');
			int mon = Convert.ToInt16(str[0]);
			int day = Convert.ToInt16(str[1]);
			int yea = Convert.ToInt16(str[2]);
			return new DateTime(yea,mon,day);
		}
				
		/// <summary>
		/// receive time string like "hh.mm"
		/// fix time to correct form
		/// ex  1.65  -> 2.05
		/// </summary>
		/// <param name="time"></param>
		/// <returns></returns>
		public static string fixTimeValue(string time)
		{			
			if(time.Trim() == "0") return "";
			if( time != null && time.Trim().Length > 0 && time.IndexOf(".") == -1) return time+".00";
			if(time.IndexOf(".")>=0)
			{
				string[] str = ("0"+time).Split('.');
				int hou = Convert.ToInt16(str[0]);
				int min = Convert.ToInt16(str[1]);
				if( str[1].Trim().Length == 1 && min >= 6 && min < 10)
					time = (hou + 1) + "." + (min - 6);
	
				if( min >= 60 && min < 70)
					time = (hou + 1) + ".0" + ( min - 60);
				if( min >= 60 && min >= 70)
					time = (hou + 1) + "." + ( min - 60);
			}
			if(time.IndexOf(".") == time.Length-2) return time+"0";
			return time;
		}
	
		//get percentage(double) from time string
		//ex: 2.30 -> 2.5, 2.45 -> 2.75
		public static double time2Percent(string time)
		{
			if(time == null || time.Length == 0) return 0.0;
			else if(time.IndexOf(".") == -1) return Convert.ToDouble(time);
			else
			{
				time = fixTimeValue(time);
				string[] str = time.Split('.');
				str[1] =  Convert.ToInt32((Convert.ToInt32( str[1] ) * 100 ) / 60) + "";
				if(str[1].Length == 1) return Convert.ToDouble( str[0] +".0"+ str[1]);
				return Convert.ToDouble( str[0] +"."+ str[1]);
			}
		}
	
		//get correct time string from percentage string
		public static string percent2Time(string percent)
		{
			if(percent == null || percent.Length == 0) return "0.0";
			else if(percent.IndexOf(".") == -1) return percent+".0";
			else
			{
				string[] str = percent.Split('.');
				str[1] =  Convert.ToInt32((Convert.ToInt32( str[1] ) * 60 ) / 100) + "";
				if(str[1].Length == 1) return fixTimeValue( str[0] +".0"+ str[1]);
				return fixTimeValue( str[0] +"."+ str[1]);
			}
		}
	
		//get total minute from time string
		//ex: 1.30 --> 90
		public static int time2Minute(string time){
			if(time == null || time.Length == 0) return 0;
			else if( StringLib.indexOfAny(time,".:") == -1 ) return Convert.ToInt32(time) * 60;
			else {
				string[] str = StringLib.splitByAny(time, ".:");
				return (Convert.ToInt32(str[0]) * 60) + Convert.ToInt32(str[1]);
			}
		}
	
		//get time string from minute
		//ex: 90 -> 1.30
		public static string minute2Time(int minutes, char separator)
		{			
			return minute2Time( minutes ).Replace(".", separator.ToString());
		}
		
		public static string minute2Time(int minutes)
		{
			if(minutes < 10) return fixTimeValue( "0.0"+minutes );
			else if(minutes >= 10 && minutes<60) return fixTimeValue( ("0.") + minutes );
			else if(minutes >= 60)
			{
				int hou = minutes / 60;
				int min = minutes - (hou * 60);
				if(min<10) return fixTimeValue( hou + (".0") + min );
				else return fixTimeValue( "" + hou + "." + min );
			}
			return minutes.ToString();
		}
		
		
		public static string[] getWeekDate(DateTime dat)
		{			
			//get index day of week
			string dayOfWeek = "MonTueWedThuFriSatSun";
			int    dayIndex  = dayOfWeek.IndexOf( dat.ToLongDateString().Substring(0,3) ) / 3;
			if(dayIndex > 0) dayIndex = - dayIndex;
				
			//get max day of current month and previous month
			int MaxDayOfMonth = 31;
			string month30 = ",4,6,9,11,";
			if(month30.IndexOf(","+dat.Month+",") >= 0) MaxDayOfMonth = 30;
			if(dat.Month == 2) MaxDayOfMonth = 28;
			if(dat.Month == 2 && (dat.Year % 4 == 0 || dat.Year % 100 == 0) ) MaxDayOfMonth = 29;
	
			int MaxDayOfPreviousMonth = 31;
			if(month30.IndexOf(","+(dat.Month - 1)+",") >= 0) MaxDayOfPreviousMonth = 30;
			if((dat.Month - 1) == 2) MaxDayOfPreviousMonth = 28;
			if((dat.Month - 1) == 2 && (dat.Year % 4 == 0 || dat.Year % 100 == 0) ) MaxDayOfPreviousMonth = 29;
	
	
			//get day for selected week
			int[]    returnDay	  = new int[7];
			string[] returnDayStr = new string[7];
			int firstIndex = 0;
			for(int i = dayIndex;i< dayIndex + 7;i++)
			{
				returnDay[firstIndex] = (dat.Day + i);
				returnDayStr[firstIndex] = dat.Month + "/" + (dat.Day + i) + "/" + dat.Year;
	
				if(returnDay[firstIndex] > MaxDayOfMonth)
				{
					returnDay[firstIndex] = returnDay[firstIndex] - MaxDayOfMonth;
					returnDayStr[firstIndex] = (dat.Month + 1) + "/" + (returnDay[firstIndex]) + "/" + dat.Year;
					if(dat.Month == 12) returnDayStr[firstIndex] = "1/" + (returnDay[firstIndex]) + "/" + (dat.Year+1);
				}
				if(returnDay[firstIndex] <= 0)
				{
					returnDay[firstIndex] = MaxDayOfPreviousMonth + returnDay[firstIndex];
					returnDayStr[firstIndex] = (dat.Month - 1) + "/" + (returnDay[firstIndex]) + "/" + dat.Year;
					if(dat.Month == 1) returnDayStr[firstIndex] = "12/" + (returnDay[firstIndex]) + "/" + (dat.Year-1);
				}
	
				firstIndex++;
			}
			return returnDayStr;
		}
	
		public static int[] getWeekDateInt(DateTime dat)
		{
			string[] date = getWeekDate(dat);
			int[] returndate = new int[date.Length];
			for(int i=0;i<date.Length;i++)
				returndate[i] = Convert.ToInt16( date[i].Split('/')[1] );
			return returndate;
		}
		
		//get total time of all rows with specific column of a table in dataset.	
		public static string getTotalTime(System.Data.DataSet ds, int tableIndex, int columnIndex)
		{		
			int total = 0;
			if(ds != null && ds.Tables[tableIndex].Rows.Count > 0)
				for(int i=0;i<ds.Tables[tableIndex].Rows.Count;i++)
					total+= time2Minute( ds.Tables[tableIndex].Rows[i][columnIndex].ToString() );
			return minute2Time(total);
			 
		}
		
		//get total time of all rows with specific column of a table in dataset.	
		//with array index of columns and its value to match correlative
		public static string getTotalTime(System.Data.DataSet ds, int tableIndex, int columnIndex,int[] conditionColumnIndex,string[] conditionColumnValue )
		{		
			int total = 0;
			if(ds != null && ds.Tables[tableIndex].Rows.Count > 0)
				for(int i=0;i<ds.Tables[tableIndex].Rows.Count;i++)
				{
					bool isCorrect = true;
					for(int j=0;j<conditionColumnIndex.Length;j++)
						if(ds.Tables[tableIndex].Rows[i][conditionColumnIndex[j]].ToString() != conditionColumnValue[j])
							isCorrect = false;
					
					if(isCorrect)
					total+= time2Minute( ds.Tables[tableIndex].Rows[i][columnIndex].ToString() );
				}
			return minute2Time(total);			 
		}	
	
		//get datetime from date string and time string
		//date: MM/dd/yyy  - time: hh:mm
		public static DateTime getDateTimeFromString(string date, string time){
			if(date.IndexOf("/") == -1 || date.IndexOf("/") == date.LastIndexOf("/") || time.IndexOf(":") == -1)
				return getDate();
			else{
				int mon = Convert.ToInt16(date.Split('/')[0]);
				int day = Convert.ToInt16(date.Split('/')[1]);
				int yea = Convert.ToInt16(date.Split('/')[2]);
				int hou = Convert.ToInt16(time.Split(':')[0]);
				int min = Convert.ToInt16(time.Split(':')[1]);
				return new DateTime(yea,mon,day,hou,min,0,0);
			}
		}
		
		
		//get next date string from passed DateTime
		public static string getNextDate(DateTime dat){
			return dat.AddDays(1).ToString("MM/dd/yyyy");
		}
		
		//get next date string from passed date string
		public static string getNextDate(string dat)
		{
			return getNextDate( DateTime.Parse( dat ) );			
		}
	
		//get previous date string from passed DateTime
		public static string getPreviousDate(DateTime dat)
		{
			return dat.AddDays(-1).ToString("MM/dd/yyyy");
		}
		
		//get previous date string from passed date string
		public static string getPreviousDate(string dat)
		{
			return getPreviousDate( DateTime.Parse( dat ) );
		}
		
		/// <summary>
		/// Compare current date with another date
		/// </summary>
		/// <param name="currentDate"></param>
		/// <param name="DateToCompare"></param>
		/// <returns>0: equal, 1: higher, -1: lower </returns>
		public enum CompareType{ higher=1, equal=0, lower=-1 }
		public static CompareType compareDate( DateTime currentDate, DateTime DateToCompare ){			
			if( currentDate.Year > DateToCompare.Year ) return CompareType.higher;
			if( currentDate.Year < DateToCompare.Year ) return CompareType.lower;
			
			if( currentDate.Month > DateToCompare.Month ) return CompareType.higher;
			if( currentDate.Month < DateToCompare.Month ) return CompareType.lower;
			
			if( currentDate.Day > DateToCompare.Day ) return CompareType.higher;
			if( currentDate.Day < DateToCompare.Day ) return CompareType.lower;
			
			return CompareType.equal;
		}
		
		public static CompareType compareDate( string currentDate, string DateToCompare ){
			return compareDate( DateTime.Parse( currentDate ), DateTime.Parse( DateToCompare ) );
		}
		
	
         private static double timeZone = 7.0;
         //Lấy Ngày Julius
         private static long getJulius(int intNgay, int intThang, int intNam)
         {
             int a, y, m, jd;
             a = (int)((14 - intThang) / 12);
             y = intNam + 4800 - a;
             m = intThang + 12 * a - 3;
			 jd = intNgay + (int)((153 * m + 2) / 5) + 365 * y + (int)(y / 4) - (int)(y / 100) + (int)(y / 400) - 32045;
             if (jd < 2299161)
             {
                 jd = intNgay + (int)((153 * m + 2) / 5) + 365 * y + (int)(y / 4) - 32083;
             }
             return jd;
         }

         // Từ ngày Julius chuyển ra ngày thường
         private static string jdToDate(int jd)
         {
             int a, b, c, d, e, m; 
             int day, month, year;
             if (jd > 2299160)
             { // After 5/10/1582, Gregorian calendar
                 a = jd + 32044;
                 b = (int)((4 * a + 3) / 146097);
                 c = a - (int)((b * 146097) / 4);
             }
             else
             {
                 b = 0;
                 c = jd + 32082;
             }
             d = (int)((4 * c + 3) / 1461);
             e = c - (int)((1461 * d) / 4);
             m = (int)((5 * e + 2) / 153);
             day = e - (int)((153 * m + 2) / 5) + 1;
             month = m + 3 - 12 * (int)(m / 10);
             year = b * 100 + d - 4800 + (int)(m / 10);
             return day.ToString() + "/" + month.ToString() + "/" + year.ToString(); 
         }

         //Tính ngày Sóc
         private static int getNewMoonDay(int k)
         {
			double T, T2, T3, dr, Jd1, M, Mpr, F, C1, deltat, JdNew;
			T = k / 1236.85;
			T2 = T * T;
			T3 = T2 * T;
			dr = Math.PI / 180;
			Jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * T2 - 0.000000155 * T3;
			// Mean new moon
			Jd1 = Jd1 + 0.00033 * Math.Sin((166.56 + 132.87 * T - 0.009173 * T2) * dr); 
			// Sun's mean anomaly
			M = 359.2242 + 29.10535608 * k - 0.0000333 * T2 - 0.00000347 * T3;
			// Moon's mean anomaly 
			Mpr = 306.0253 + 385.81691806 * k + 0.0107306 * T2 + 0.00001236 * T3; 
			// Moon's argument of latitude
			F = 21.2964 + 390.67050646 * k - 0.0016528 * T2 - 0.00000239 * T3;
			C1 = (0.1734 - 0.000393 * T) * Math.Sin(M * dr) + 0.0021 * Math.Sin(2 * dr * M);
			C1 = C1 - 0.4068 * Math.Sin(Mpr * dr) + 0.0161 * Math.Sin(dr * 2 * Mpr);
			C1 = C1 - 0.0004 * Math.Sin(dr * 3 * Mpr);
			C1 = C1 + 0.0104 * Math.Sin(dr * 2 * F) - 0.0051 * Math.Sin(dr * (M + Mpr));
			C1 = C1 - 0.0074 * Math.Sin(dr * (M - Mpr)) + 0.0004 * Math.Sin(dr * (2 * F + M));
			C1 = C1 - 0.0004 * Math.Sin(dr * (2 * F - M)) - 0.0006 * Math.Sin(dr * (2 * F + Mpr));
			C1 = C1 + 0.0010 * Math.Sin(dr * (2 * F - Mpr)) + 0.0005 * Math.Sin(dr * (2 * Mpr + M));
			if (T < -11)
			{
			deltat = 0.001 + 0.000839 * T + 0.0002261 * T2 - 0.00000845 * T3 - 0.000000081 * T * T3;
			}
			else
			{
			deltat = -0.000278 + 0.000265 * T + 0.000262 * T2;
			}
			JdNew = Jd1 + C1 - deltat;
			return (int)(JdNew + 0.5 + timeZone / 24);
         }

         //Tính toạ độ mặt trời
         private static int getSunLongitude(int jdn)
         {
			double T, T2, dr, M, L0, DL, L;
			// Time in Julian centuries from 2000-01-01 12:00:00 GMT
			T = (jdn - 2451545.5 - timeZone / 24) / 36525;    
			T2 = T * T;
			dr = Math.PI / 180; // degree to radian
			// mean anomaly, degree
			M = 357.52910 + 35999.05030 * T - 0.0001559 * T2 - 0.00000048 * T * T2;             L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T2; // mean longitude, degree
			DL = (1.914600 - 0.004817 * T - 0.000014 * T2) * Math.Sin(dr * M);
			DL = DL + (0.019993 - 0.000101 * T) * Math.Sin(dr * 2 * M) + 0.000290 * Math.Sin(dr * 3 * M);
			L = L0 + DL; // true longitude, degree
			L = L * dr;
			L = L - Math.PI * 2 * (int)(L / (Math.PI * 2)); // Normalize to (0, 2*PI)
			return (int)(L / Math.PI * 6);
         }

         //Tìm ngày bắt đầu tháng 11 âm lịch 
         private static int getLunarMonthll(int intNam)
         {
             double k, off, nm, sunLong;
             off = getJulius(31, 12, intNam) - 2415021;
             k = (int)(off / 29.530588853);
             nm = getNewMoonDay((int)k);
             sunLong = getSunLongitude((int)nm); // sun longitude at local midnight
             if (sunLong >= 9)
             {
                 nm = getNewMoonDay((int)k - 1);
             }
             return (int)nm;
         }

         //Xác định tháng nhuận
         private static int getLeapMonthOffset(double a11)
         {
             double last, arc;
             int k, i;
             k = (int)((a11 - 2415021.076998695) / 29.530588853 + 0.5);
             last = 0;
             i = 1; // We start with the month following lunar month 11
             arc = getSunLongitude((int)getNewMoonDay((int)(k + i)));
             do
             {
                 last = arc;
                 i++;
                 arc = getSunLongitude((int)getNewMoonDay((int)(k + i)));
             } while (arc != last && i < 14);
             return i - 1;
         }

         //Đổi ngày dương ra ngày âm
         public static string convertSolar2Lunar(DateTime date)
         {
         	int intNgay = date.Day, intThang = date.Month, intNam = date.Year;         	
         	
             double dayNumber, monthStart, a11, b11, lunarDay, lunarMonth, lunarYear;
             //double lunarLeap;
             int k, diff;
             dayNumber = getJulius(intNgay,intThang,intNam);
             k = (int)((dayNumber - 2415021.076998695) / 29.530588853);
             monthStart = getNewMoonDay(k + 1);
             if (monthStart > dayNumber)
             {
                 monthStart = getNewMoonDay(k);
             }
             a11 = getLunarMonthll(intNam);
             b11 = a11;
             if (a11 >= monthStart)
             {
                 lunarYear = intNam;
                 a11 = getLunarMonthll(intNam - 1);
             }
             else
             {
                 lunarYear = intNam + 1;
                 b11 = getLunarMonthll(intNam + 1);
             }
             lunarDay = dayNumber - monthStart + 1;
             diff = (int)((monthStart - a11) / 29);
             //lunarLeap = 0;
             lunarMonth = diff + 11;
             if (b11 - a11 > 365)
             {
                 int leapMonthDiff = getLeapMonthOffset(a11);
                 if (diff >= leapMonthDiff)
                 {
                     lunarMonth = diff + 10;
                     if (diff == leapMonthDiff)
                     {
                         //lunarLeap = 1;
                     }
                 }
             }
             if (lunarMonth > 12)
             {
                 lunarMonth = lunarMonth - 12;
             }
             if (lunarMonth >= 11 && diff < 4)
             {
                 lunarYear -= 1;
             }
             string strNgay = lunarDay.ToString();
             string strThang = lunarMonth.ToString();
             string strNam = lunarYear.ToString();
             return strNgay + "/" + strThang + "/" + strNam;
         }
 	}
 }
